package com.wangp.procurement.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wangp.procurement.convert.GoodsConverter;
import com.wangp.procurement.dto.ProcurementManagementDto;
import com.wangp.procurement.mapper.GoodsMapper;
import com.wangp.procurement.mapper.ProcurementManagerMapper;
import com.wangp.procurement.po.GoodsDO;
import com.wangp.procurement.po.ProcurementManagementDO;
import com.wangp.procurement.service.ProcurementManagerService;
import com.wangp.procurement.vo.GoodsVO;
import com.wangp.procurement.vo.InsertManagementDTO;
import com.wangp.procurement.vo.ProcurementManagementVO;
import com.wangp.procurement.vo.UpsertProcurementManagementDTO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 采购管理的业务实现层.
 *
 * @author WangPing2
 * <p>createDate 2024-11-17</p>
 **/
@Service
public class ProcurementManagerServiceImpl implements ProcurementManagerService {

    @Autowired
    private ProcurementManagerMapper procurementManagerMapper;

    @Autowired
    private GoodsMapper goodsMapper;


    private  GoodsConverter convertToGoodsDO;


    private void validate(InsertManagementDTO insertManagementDTO) {
        // todo 不可能这么简单
        Assert.notNull(insertManagementDTO, "采购管理对象不能为空");
        Assert.isTrue(!CollectionUtils.isEmpty(insertManagementDTO.getGoodsList()), "货物为空");
        // 管理：检验唯一键 （唯一键： 期限+类型）
        QueryWrapper<ProcurementManagementDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("period", insertManagementDTO.getPeriod());
        queryWrapper.eq("type", insertManagementDTO.getType());
        queryWrapper.eq("status", 0);
        ProcurementManagementDO procurementManagementDO = procurementManagerMapper.selectOne(queryWrapper);
        Assert.isTrue(procurementManagementDO == null, "已经存在期限：" + insertManagementDTO.getPeriod() + ", 类型" + insertManagementDTO.getType() + "的货物管理");
        // ==============================================================
        // 校验货物
        Set<String> uniqueKeys = new HashSet<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM");
        for (GoodsVO goodsVO : insertManagementDTO.getGoodsList()) {
            // 校验日期类型
            try {
                sdf.parse(goodsVO.getEffectiveDate());
            } catch (ParseException e) {
                throw new IllegalArgumentException("商品有效期格式错误，期望：yyyy.MM。 实际：" + goodsVO.getEffectiveDate());
            }

            String uniqueKey = ""; // 根据类型构建唯一键
            // todo  校验当前这货物list不符合预期
            if(("按年").equals(insertManagementDTO.getType())){
                // 货物：检验唯一键 按年 （唯一键： 采购地+有效期）
                uniqueKey = "采购地:"+goodsVO.getProcurementPlace() +"有效期:"+ goodsVO.getEffectiveDate();
            } else if(("按月").equals(insertManagementDTO.getType())){
                // 货物：检验唯一键 按月 （唯一键： 采购地+目的地）
                uniqueKey = "采购地:"+ goodsVO.getProcurementPlace() + "目的地"+goodsVO.getDestination();
            }
            // 校验唯一键是否已存在
            if (!uniqueKeys.add(uniqueKey)) {
                // 如果唯一键已存在，表示有重复，可以抛出异常或者进行其他处理
                throw new IllegalArgumentException("Duplicate unique key for goods: " + uniqueKey);
            }
        }

    }

    private void validate(UpsertProcurementManagementDTO upsertProcurementManagementDTO) {

    }

    /**
     * 采购管理---新增
     * @param insertManagementDTO
     * @return 新增数据
     */
    @Transactional
    public void   saveManageWithGoods(final InsertManagementDTO insertManagementDTO) {
        //0.非空校验
        validate(insertManagementDTO);
        ProcurementManagementDO procurementManagementDO = new ProcurementManagementDO();
        BeanUtils.copyProperties(insertManagementDTO,procurementManagementDO);
        //todo 新增 管理   插入1条数据
        procurementManagerMapper.insertManager(procurementManagementDO);

        Integer managementId = procurementManagementDO.getId();

        //货物表  可以实现批量新增
        List<GoodsVO> goodsList = insertManagementDTO.getGoodsList();
        List<GoodsDO> goodsDOList = GoodsConverter.convertToGoodsDOList(goodsList);

        goodsDOList.forEach(goodsDO->{
            goodsDO.setProcurementManagementId(managementId);
        });
        //插入数据----批量
        goodsMapper.insertBatchGoods(goodsDOList);

    }
    /**
     * 采购管理---根据id 查询管理对应的货物
     * @param id
     * @return UpsertProcurementManagementDTO
     */
    @Override
    public UpsertProcurementManagementDTO getByIdWithGoods(final Integer id) {
        //查管理
        ProcurementManagementDO managementDO = procurementManagerMapper.selectProcurementManagementById(id);
        //查货物
        List<GoodsDO> goodsDO = goodsMapper.findByProcurementManagementId(id);
        //封装
        UpsertProcurementManagementDTO upsertProcurementManagementDTO=new UpsertProcurementManagementDTO();
        BeanUtils.copyProperties(managementDO,upsertProcurementManagementDTO);
        upsertProcurementManagementDTO.setGoodsList(GoodsConverter.convertToGoodsVOList(goodsDO));
        return upsertProcurementManagementDTO;
    }

    //根据id修改管理信息和对应的货物信息  0 表示true  1 表示false

    /**
     * 根据id修改管理信息和对应的货物信息
     * @param upsertProcurementManagementDTO
     */
    @Override
    public void updateWhitGoods(final UpsertProcurementManagementDTO upsertProcurementManagementDTO) {
      //  validate(upsertProcurementManagementDTO);
/*
        ProcurementManagementDO procurementManagementDO = new ProcurementManagementDO();
        BeanUtils.copyProperties(upsertProcurementManagementDTO,procurementManagementDO);
        //修改管理表-------仅需改name
        procurementManagerMapper.updateManage(procurementManagementDO);*/
        updateManage(upsertProcurementManagementDTO);
        //删除原来的货物信息
        goodsMapper.deleteGoods(upsertProcurementManagementDTO.getId());
        //新增新的货物数据
        List<GoodsVO> goodsList = upsertProcurementManagementDTO.getGoodsList();
        List<GoodsDO> goodsDOList = GoodsConverter.convertToGoodsDOList(goodsList);
        if(!goodsDOList.isEmpty()){
            goodsDOList.forEach(goodsDO -> {
                goodsDO.setId(upsertProcurementManagementDTO.getId());
            });
            //插入数据----批量
            goodsMapper.insertBatchGoods(goodsDOList);
        }
    }


    // 管理修改提出来一个方法
    public void updateManage(final UpsertProcurementManagementDTO upsertProcurementManagementDTO) {
        ProcurementManagementDO procurementManagementDO = new ProcurementManagementDO();
        BeanUtils.copyProperties(upsertProcurementManagementDTO, procurementManagementDO);
        //修改管理表-------仅需改name
        procurementManagerMapper.updateManage(procurementManagementDO);
    }

    /**
     * 采购管理---修改    方法二 比较
     * @param id
     * @return UpsertProcurementManagementDTO
     */
    /**
     * 1. 查出数据库内该采购管理下的所有货物
     * 2. 比较前端传过来的货物和数据库内的货物
     * 3. 如果有相同id的，则有嫌疑修改
     * 4. 如果没有id的，则新增
     * 5. 如果数据库内的货物不在前端传过来的货物内，则删除
     * compare 后获取三个list，分别是修改 新增 删除
     * last：执行数据库内的
     */
    @Override
    public UpsertProcurementManagementDTO updateWhitGoodsNew(final UpsertProcurementManagementDTO upsertProcurementManagementDTO) {

       // 1. 根据id 查询管理对应的货物
        ProcurementManagementDO requestDO = convertUpsertProcurementManagementVOToDO(
            upsertProcurementManagementDTO);
        Integer id = requestDO.getId();

        updateManage(upsertProcurementManagementDTO);

        List<GoodsVO> requestGoodList = upsertProcurementManagementDTO.getGoodsList();
        List<GoodsVO> dbGoodList = getByIdWithGoods(id).getGoodsList();

        List<GoodsVO> insertList = new ArrayList<>();
        List<GoodsVO> updateList = new ArrayList<>();
        List<GoodsVO> delList = new ArrayList<>();
        // 2. 比较前端传过来的货物和数据库内的货物
        compare(requestGoodList, dbGoodList, insertList, updateList, delList);

        // 3. 执行数据库操作
        executeDatabaseOperations(insertList, updateList, delList);

        return upsertProcurementManagementDTO;
    }
    private void executeDatabaseOperations(List<GoodsVO> insertList, List<GoodsVO> updateList, List<GoodsVO> delList) {
        // 执行新增操作
        List<GoodsDO> insertGoodList = GoodsConverter.convertToGoodsDOList(insertList);
        goodsMapper.insertBatchGoods(insertGoodList);

        // 执行修改操作
        List<GoodsDO> updateGoodList = GoodsConverter.convertToGoodsDOList(updateList);
        updateList.forEach(goods -> {
            goodsMapper.executeUpdate(updateGoodList);
        });

        // 执行删除操作

        delList.forEach(goods -> {
            goodsMapper.deleteGoods(goods.getId());
        });
    }

    private void compare(List<GoodsVO> requestGoodList, List<GoodsVO> dbGoodList, List<GoodsVO> insertList, List<GoodsVO> updateList, List<GoodsVO> delList) {

        Map<Integer, GoodsVO> dbGoodsMap = dbGoodList.stream()
            .collect(Collectors.toMap(GoodsVO::getId, Function.identity()));

        // 新增
        // todo 也可以，这样判断不好
        requestGoodList.forEach(requestGood -> {
            if (!dbGoodsMap.containsKey(requestGood.getId())) {
                insertList.add(requestGood);
            }
        });

        // 修改
        // todo 有问题
        requestGoodList.forEach(requestGood -> {
            GoodsVO dbGood = dbGoodsMap.get(requestGood.getId());
            if (dbGood != null && !dbGood.equals(requestGood)) {
                updateList.add(requestGood);
            }
        });

        // 删除
        // todo 有问题
        dbGoodList.forEach(dbGood -> {
            if (!requestGoodList.contains(dbGood)) {
                delList.add(dbGood);
            }
        });

    }

    /**
     * 采购管理---失效
     * @param id
     * @return id
     */
    @Override
    @Transactional
    public Integer disableInfo( Integer id) {
        return   procurementManagerMapper.disableInfo(id);
    }


    /**
     * 采购管理---列表
     * @param procurementManagementDto
     * @return 分页信息
     */
    @Override
    public ProcurementManagementDto queryPage(final ProcurementManagementDto procurementManagementDto) {

        Assert.notNull(procurementManagementDto, "列表参数为空");

        int page = procurementManagementDto.getPage();
        int size = procurementManagementDto.getSize();
        int offset = (page - 1) * size;
        // 分页数据
        List<ProcurementManagementDO> list = procurementManagerMapper.findPageData(offset, size);
        // 查询总记录数
        int total = procurementManagerMapper.getTotalCount();

        // 封装分页结果
        ProcurementManagementDto result = new ProcurementManagementDto();
        result.setData(list);
        result.setTotal(total);
        result.setPage(page);
        result.setSize(size);

        return result;

    }

    /**
     * 采购管理--查询详情
     * @param id
     * @return ProcurementManagementVO
     */
    @Override
    public ProcurementManagementVO queryInfoById(final Integer id) {
        //通过id查询管理的详情
        ProcurementManagementDO procurementManagementDO = procurementManagerMapper
            .selectProcurementManagementById(id);
        return convertProcurementManagementDOToVO(procurementManagementDO);
    }


    //转换 DOToVO
    public  ProcurementManagementVO convertProcurementManagementDOToVO (ProcurementManagementDO procurementManagementDO){

        ProcurementManagementVO procurementManagementVO = new ProcurementManagementVO();
        BeanUtils.copyProperties(procurementManagementDO, procurementManagementVO);
        // 查询采购管理的货物信息 返回List<GoodsDO>
        List<GoodsDO> goodsDOList = goodsMapper.selectGoodsByProcurementManagementId(procurementManagementDO.getId());

        // 转换货物DO列表为货物VO列表
        List<GoodsVO> goodsVOList = new ArrayList<>();
        for (GoodsDO goodsDO : goodsDOList) {
            GoodsVO goodsVO = GoodsConverter.convertToGoodsVO(goodsDO);
            goodsVOList.add(goodsVO);
        }
        // 设置货物VO列表到采购管理VO
        procurementManagementVO.setGoodsList(goodsVOList);
        return procurementManagementVO;
    }

    public  ProcurementManagementDO convertUpsertProcurementManagementVOToDO(
        UpsertProcurementManagementDTO upsertProcurementManagementDTO){
        ProcurementManagementDO procurementManagementDO = new ProcurementManagementDO();
        procurementManagementDO.setId(upsertProcurementManagementDTO.getId());
        procurementManagementDO.setName(upsertProcurementManagementDTO.getName());
        return procurementManagementDO;
    }
    public  ProcurementManagementDO convertVOToDO (ProcurementManagementVO procurementManagementVO){
        ProcurementManagementDO procurementManagementDO = new ProcurementManagementDO();
        procurementManagementDO.setId(procurementManagementVO.getId());
        procurementManagementDO.setType(procurementManagementVO.getType());
        procurementManagementDO.setName(procurementManagementVO.getName());
        procurementManagementDO.setPeriod(procurementManagementVO.getPeriod());
        return procurementManagementDO;
    }

    /**
     * 逻辑
     * 前段传id了，修改
     *        采购管理的内容（名称/期限 不能修改）
     *        主要修改的是货物
     * 前端没传id，新增
     *
     *
     *
     * @param procurementManagementVo
     * @return
     */
  /*  @Override
    @Transactional
    public Integer saveOrUpdateGoodsManage(ProcurementManagementVO procurementManagementVo) {

        this.validate(procurementManagementVo);

        //0.修改管理记录
        //Integer isExist = procurementManagerMapper.isProcurementManagement(procurementManagementVo.getId());

        if (Objects.nonNull(procurementManagementVo.getId())){
            // 修改
            // method 1 简单:
            */
    /**
             * 1. 先把对应采购管理内的所有货物删除
             * 2. 再把新的货物插入
             */
    /*
            // method 2 更高大上:
            */
    /**
             * 1. 查出数据库内该采购管理下的所有货物
             * 2. 比较前端传过来的货物和数据库内的货物
             * 3. 如果有相同id的，则有嫌疑修改
             * 4. 如果没有id的，则新增
             * 5. 如果数据库内的货物不在前端传过来的货物内，则删除
             * compare 后获取三个list，分别是修改 新增 删除
             * last： exeu db
             *
             *
             *
             *
             * 例如：
             *  数据库内
             *  [
             *      {
             *          1
             *          good1,
             *          xian,
             *          2024.01
             *      },{
             *          2
             *          good2,
             *          shanghai,
             *          2024.01
             *      },{
             *          3
             *          good3,
             *          guangzhou,
             *          2024.01
             *      }
             *  ]
             *
             *
             *  // 前端传的
             *  //[
             *      {
             *          1
             *          good1,
             *          beijing,
             *          2024.01
             *      },{
             *
             *          good4,
             *          wuhan,
             *          2024.01
             *      },{
             *          3
             *          good3,
             *          guangzhou,
             *          2024.01
             *      }
             *  ]
             */
    /*


            procurementManagerMapper.updateProcurementManagement(procurementManagementVo);
            return 0;
        } else {
            // 0. 填充基本信息
            procurementManagementVo.setStatus(ProcurementManagementEnum.EFFECTIVE.getValue());
            procurementManagementVo.setCreationBy("wangp");
            procurementManagementVo.setModifiedBy("wangp");
            // 1. 新增采购管理记录
            Integer procurementManagementId = procurementManagerMapper.insertProcurementManagement(procurementManagementVo);
            // 2. 批量新增货物
            List<GoodsVO> goodsList = procurementManagementVo.getGoodsList();
//           todo if (goodsList != null) {
            // 逻辑没问题
            if (!CollectionUtils.isEmpty(goodsList)) {
                for (GoodsVO goodsVo : goodsList) {
                    // 在公司这里的goodsvo肯定要转
                    goodsVo.setProcurementManagementId(procurementManagementId);
                    procurementManagerMapper.insertGoods(goodsVo);
                }
            }
            return procurementManagementId;
        }
    }*/








/*
    @Override
    // todo 没加事务
    public Integer deleteInfo( Integer id) {
// 物理删除
        // todo 改成逻辑删除
        // 货物管理删了，里面的货物不删吗？？

        return procurementManagerMapper.deleteById(id);
    }
*/

}